﻿#include "Windows.h"
#include "Commdlg.h"
#include <tchar.h>
#include "zyFileDialog.h"


BlackMoonUI::zyFileDialog::zyFileDialog()
{
	SetMember(L"this", (LONG_PTR)this);
	SetMember(L"StartPosition", 开始位置_居中父窗口);
}
BlackMoonUI::zyFileDialog::~zyFileDialog()
{
	OPENFILENAME* ofn = (OPENFILENAME*)GetMember(L"pOpenFileName");
	if (ofn != nullptr) {
		if (ofn->lpstrTitle != nullptr)
			delete ofn->lpstrTitle;
		if (ofn->lpstrFile != nullptr)
			delete ofn->lpstrFile;
		if (ofn->lpstrInitialDir != nullptr)
			delete ofn->lpstrInitialDir;
		if (ofn->lpstrDefExt != nullptr)
			delete ofn->lpstrDefExt;
		delete ofn;
	}
}
LRESULT CALLBACK BlackMoonUI::zyFileDialog::OFNHookProc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) {
	switch (message) {
	case WM_INITDIALOG:
	{
		OPENFILENAME* ofn = reinterpret_cast<OPENFILENAME*>(lParam);
		HWND hwndParent = GetParent(hdlg);
		zyFileDialog* Dialog = reinterpret_cast<zyFileDialog*>(ofn->lCustData);
		if (Dialog) {
			Dialog->WinProc_SubClass(hwndParent, message, wParam, lParam);
			Dialog->_MoveToStartPosition(hwndParent);
			TRegEvent* evtPtr = Dialog->GetRegEvent(L"OnCreate");
			if (evtPtr != nullptr)
				LRESULT ret = evtPtr->handler<int>(hwndParent);
		}
	}
	break;
	case WM_NOTIFY:
	{
		NMHDR* nm(reinterpret_cast<NMHDR*>(lParam));//reinterpret_cast 转指针 static_cast 转变量
		if (nm->code == CDN_SELCHANGE) {
			zyObject* Dialog = zyEnv::getInstance().getWndObject(GetParent(hdlg));
			void* pOpenFileName = Dialog->getPtrData(L"pOpenFileName");
			if (pOpenFileName != 0) {
				UINT cbLength = (UINT)SendMessage(GetParent(hdlg), CDM_GETSPEC, 0, 0);
				cbLength = cbLength * 2 + 260;
				OPENFILENAME* ofn = reinterpret_cast<OPENFILENAME*>(pOpenFileName);
				if (ofn->nMaxFile < cbLength) {
					if (ofn->lpstrFile)
						delete ofn->lpstrFile;
					// 分配足够的空间来存储文件路径和文件名  
					WCHAR* szBuffer = new WCHAR[cbLength * 2];
					ZeroMemory(szBuffer, sizeof(WCHAR) * MAX_PATH);
					ofn->lpstrFile = szBuffer;
					ofn->nMaxFile = cbLength;
				}
			}
		}
		break;
	}
	case CDN_TYPECHANGE:
	{
		zyObject* Dialog = zyEnv::getInstance().getWndObject(GetParent(hdlg));
		TRegEvent* evtPtr = Dialog->getRegEvent(L"OnTypeChange");
		if (evtPtr != nullptr) {
			OFNOTIFY* ofnTify = reinterpret_cast<OFNOTIFY*>(lParam);
			void* pOpenFileName = Dialog->getPtrData(L"pOpenFileName");
			if (pOpenFileName != 0) {
				OPENFILENAME* ofn = reinterpret_cast<OPENFILENAME*>(pOpenFileName);
				if (ofnTify->lpOFN)
					ofn = ofnTify->lpOFN;
				LRESULT ret = evtPtr->handler<int>(GetParent(hdlg), ofn->nFilterIndex);
			}
		}
		break;
	}
	case CDN_INITDONE:
	{
		zyObject* Dialog = zyEnv::getInstance().getWndObject(GetParent(hdlg));
		TRegEvent* evtPtr = Dialog->getRegEvent(L"OnInitDone");
		if (evtPtr != nullptr)
			int ret = evtPtr->handler<int>(GetParent(hdlg));
		break;
	}
	case CDN_FILEOK:
	{
		zyObject* Dialog = zyEnv::getInstance().getWndObject(GetParent(hdlg));
		TRegEvent* evtPtr = Dialog->getRegEvent(L"OnFlieOk");
		if (evtPtr != nullptr) {
			OFNOTIFY* ofnTify = reinterpret_cast<OFNOTIFY*>(lParam);
			void* pOpenFileName = Dialog->getPtrData(L"pOpenFileName");
			if (pOpenFileName != 0) {
				OPENFILENAME* ofn = reinterpret_cast<OPENFILENAME*>(pOpenFileName);
				if (ofnTify->lpOFN)
					ofn = ofnTify->lpOFN;
				LRESULT ret = evtPtr->handler<int>(GetParent(hdlg), ofn->nFilterIndex);
				if (ret)
					SetWindowLongPtr(hdlg, DWLP_MSGRESULT, ret);
				return ret;
			}
		}
		break;
	}
	}
	return 0;
}

bool BlackMoonUI::zyFileDialog::保存(HWND 参数_父窗口)
{
	OPENFILENAME* pOpenFileName = (OPENFILENAME*)GetMember(L"pOpenFileName");
	if (pOpenFileName == nullptr) {
		return false;
	}
	pOpenFileName->hwndOwner = 参数_父窗口;
	pOpenFileName->hInstance = zyEnv::getInstance().getHandle();
	pOpenFileName->nFileOffset = 0;
	int ret = GetSaveFileName(pOpenFileName);
	return ret != 0;
}
bool BlackMoonUI::zyFileDialog::打开(HWND 参数_父窗口)
{

	OPENFILENAME* pOpenFileName = (OPENFILENAME*)GetMember(L"pOpenFileName");
	if (pOpenFileName == nullptr) {
		return false;
	}
	pOpenFileName->hwndOwner = 参数_父窗口;
	pOpenFileName->hInstance = zyEnv::getInstance().getHandle();
	pOpenFileName->nFileOffset = 0;
	return GetOpenFileName(pOpenFileName) != 0;

	/* 	// 使用 new 动态分配 OPENFILENAME 结构
		OPENFILENAME* pOfn = new OPENFILENAME;
		ZeroMemory(pOfn, sizeof(OPENFILENAME)); // 初始化结构体，避免未定义行为

		pOfn->lStructSize = sizeof(OPENFILENAME);
		pOfn->hwndOwner = 参数_父窗口;
		pOfn->hInstance = g_hInstance;
		pOfn->nFileOffset = 0;
		pOfn->lpstrFilter = L"所有文件\0*.*\0\0";
		pOfn->lpstrInitialDir = L"D:\\";

		// 分配足够的空间来存储文件路径和文件名
		WCHAR* szBuffer = new WCHAR[MAX_PATH];
		ZeroMemory(szBuffer, sizeof(WCHAR) * MAX_PATH);
		pOfn->lpstrFile = szBuffer;
		pOfn->nMaxFile = MAX_PATH;

		// 设置标志位
		pOfn->Flags = OFN_FILEMUSTEXIST | OFN_EXPLORER;

		// 调用 GetOpenFileName
		if (GetOpenFileName(pOfn) == 0)
		{
			// 处理错误情况
			delete[] szBuffer; // 释放缓冲区内存
			delete pOfn; // 释放 OPENFILENAME 结构体内存
			return false;
		}

		// 如果 GetOpenFileName 成功，处理选定的文件
		// ...

		// 释放分配的内存
		delete[] szBuffer;
		delete pOfn;   */

		//return true;  
}
void BlackMoonUI::zyFileDialog::初始化(int 参数_选项, const std::wstring& 参数_标题, const std::wstring& 参数_文件名, const wchar_t* 参数_过滤器,
	int 参数_过滤器索引, const std::wstring& 参数_初始目录, const std::wstring& 参数_默认扩展名)
{

	OPENFILENAME* ofn = (OPENFILENAME*)GetMember(L"pOpenFileName");
	if (ofn != nullptr) {
		delete ofn;
	}

	ofn = new OPENFILENAME;
	ZeroMemory(ofn, sizeof(OPENFILENAME)); // 初始化结构体，避免未定义行为

	ofn->lStructSize = sizeof(OPENFILENAME);
	int len = (int)参数_标题.size();
	if (len != 0) {
		WCHAR* Title = new WCHAR[len + 1]; // +1 用于 null 终止符  
		wcscpy_s(Title, len + 1, 参数_标题.c_str());
		ofn->lpstrTitle = Title;
	}
	//ofn->lpstrTitle = 参数_标题.empty() ? nullptr : const_cast<LPWSTR>(参数_标题.get());  
	/* ofn->lpstrFile = (LPWSTR)参数_文件名.get();
	ofn->nMaxFile = 参数_文件名.size(); */

	// 分配足够的空间来存储文件路径和文件名  
	WCHAR* szBuffer = new WCHAR[MAX_PATH];
	ZeroMemory(szBuffer, sizeof(WCHAR) * MAX_PATH);
	ofn->lpstrFile = szBuffer;
	ofn->nMaxFile = MAX_PATH;
	if (参数_过滤器 != nullptr)
		ofn->lpstrFilter = 参数_过滤器;
	len = (int)参数_初始目录.size();
	if (len != 0) {
		WCHAR* InitialDir = new WCHAR[len + 1]; // +1 用于 null 终止符  
		wcscpy_s(InitialDir, len + 1, 参数_初始目录.c_str());
		ofn->lpstrInitialDir = InitialDir;
	}
	ofn->Flags = 参数_选项 | OFN_EXPLORER;
	ofn->nFilterIndex = 参数_过滤器索引;
	len = (int)参数_默认扩展名.size();
	if (len != 0) {
		WCHAR* strDefExt = new WCHAR[len + 1]; // +1 用于 null 终止符  
		wcscpy_s(strDefExt, len + 1, 参数_默认扩展名.c_str());
		ofn->lpstrDefExt = strDefExt;
	}
	ofn->lpfnHook = (LPOFNHOOKPROC)OFNHookProc;
	ofn->lCustData = (LPARAM)this;
	SetMember(L"pOpenFileName", (LONG_PTR)ofn);
}
std::wstring BlackMoonUI::zyFileDialog::取文件名() {//如果多选文件，返回文件路径以 换行符 分隔。失败或取消返回空文本。
	OPENFILENAME* ofn = reinterpret_cast<OPENFILENAME*>(GetMember(L"pOpenFileName"));
	if (ofn == nullptr || ofn->nFileOffset == 0) {
		return L"";// 失败或取消，返回空文本
	}
	if (ofn->Flags & OFN_ALLOWMULTISELECT) {
		// 处理多文件选择  
		std::wstring 完整路径;
		const WCHAR* ps = ofn->lpstrFile;
		if (*ps == '\0')
			return ps;// 没有选择文件
		if (*ps != '\0')
		{
			const WCHAR* ps2 = ps + _tcslen(ps) + 1;
			if (*ps2 == '\0')  // 仅选择了一个文件? 那就返回一个
				return std::wstring(ps);
			else
			{
				std::wstring strBasePath(ps);
				do
				{
					if (_tcschr(ps2, '\\') == NULL) { //成功则返回要查找字符第一次出现的位置，失败返回NULL
						完整路径.append(strBasePath + L"\\" + ps2);
						完整路径.append(L"\r\n");
					}
					else {
						完整路径.append(ps2);
					}
					ps2 += _tcslen(ps2) + 1; // 移动到下一个文件名
				} while (*ps2 != '\0');
			}
			// 移除最后一个换行符（如果有）  
			if (!完整路径.empty() && 完整路径.rfind(L"\r\n")) {
				完整路径.erase(完整路径.size() - 2, 2);
			}
		}
		return 完整路径;
	}
	// 单文件选择，直接返回文件路径  
	return std::wstring(ofn->lpstrFile);
}
int BlackMoonUI::zyFileDialog::取过滤器索引()
{
	OPENFILENAME* pOpenFileName = (OPENFILENAME*)GetMember(L"pOpenFileName");
	if (pOpenFileName == nullptr) {
		return 0;
	}
	return pOpenFileName->nFilterIndex;
}
bool BlackMoonUI::zyFileDialog::置默认扩展名(const std::wstring& 参数_默认扩展名)
{
	OPENFILENAME* ofn = (OPENFILENAME*)GetMember(L"pOpenFileName");
	if (ofn == nullptr) {
		return false;
	}
	if (ofn->lpstrDefExt != nullptr)
		delete ofn->lpstrDefExt;
	int len = (int)参数_默认扩展名.size();
	if (len != 0) {
		WCHAR* strDefExt = new WCHAR[len + 1]; // +1 用于 null 终止符  
		wcscpy_s(strDefExt, len + 1, 参数_默认扩展名.c_str());
		ofn->lpstrDefExt = strDefExt;
	}
	return true;
}
void BlackMoonUI::zyFileDialog::事件_文件类型被改变(TRegEvent* 事件指针) {//返回值：无 （整数型 hWnd，整数型 过滤器索引），备注：可在此方法中调用，文件对话框.置默认扩展名()
	SetRegEvent(L"OnTypeChange", 事件指针);
}
void BlackMoonUI::zyFileDialog::事件_初始化完成(TRegEvent* 事件指针) {//返回值：无 （整数型 hWnd），备注：当对话框的所有控件创建完成时，发送此事件
	SetRegEvent(L"OnInitDone", 事件指针);
}
void BlackMoonUI::zyFileDialog::事件_确定按钮被单击(TRegEvent* 事件指针) {//返回值：整数型【0表示默认处理，1表示阻止】 （整数型 hWnd，整数型 文件名【Unicode文本指针】）
	SetRegEvent(L"OnFlieOk", 事件指针);
}